﻿using System;
using System.ComponentModel;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading;
using EasyComm.Contracts;
using EasyComm.Hosting.Configuration;
using EasyComm.Logging;
using EasyComm.SDK.Internal;
using EasyComm.ServiceUnit;

namespace EasyComm.SDK
{
    public class EasyCommContext
    {
        private static EasyCommContext _instance = new EasyCommContext();
        private System.Threading.Timer _statusPullTimer;
        public static bool IsActive { get { return NLB.AdminInstance != null && NLB.AdminInstance.Status == ServiceStatus.Online &&
            NLB.RouterService.Status == ServiceStatus.Online && NLB.ProxyService.Status == ServiceStatus.Online; } }

        public static event LogEventHandler Log;

        public EasyCommContext()
        {
            _statusPullTimer = new System.Threading.Timer(CheckStatus, null, 0, 5000);
            //_statusPullTimer.Elapsed += new ElapsedEventHandler(statusPullTimer_Elapsed);
            //_statusPullTimer.Start();
        }

        //void statusPullTimer_Elapsed(object sender, ElapsedEventArgs e)
        //{
        //    //Thread t = new Thread(new ThreadStart(CheckStatus));
        //    //t.Start();
        //}

        private void CheckStatus(object stateInfo)
        {
            if (!IsActive)
            {
                return;
            }
        }

        #region Admin
        public static class Admin
        {
            public static event AdminServiceEventHandler<IAdminNLBContract> NLBAdminServiceChange;
            public static event AdminServiceEventHandler<IAdminSLBContract> SLBAdminServiceChange;
            public static event AdminServiceEventHandler<IAdminWorkerContract> WorkerAdminServiceChange;
            public static event SystemServiceEventHandler SystemServiceChange;
            public static event WorkerServiceEventHandler WorkerServiceChange;

            public static Uri Url
            {
                get { return NLB.AdminInstance.ListenUri; }
            }

            //public static ServiceContractCollection Contracts
            //{
            //    get { return NLB.Contracts; }
            //}

            public static AdminServiceUnitCollection<IAdminSLBContract> SystemLoadBalancerList
            {
                get { return NLB.SystemLoadBalancerList; }
            }

            public static WorkerServiceUnitCollection WorkerList
            {
                get { return NLB.WorkerList; }
            }

            public static void Initialize(Type[] serviceContractList)
            {
                OnLog(NLB.AdminInstance, MessageType.Info, "Initializing NLB...");
                NLB.AdminInstance.Service.Proxy.InitializeContracts(serviceContractList);
            }

            public static void Initialize()
            {
                OnLog(NLB.AdminInstance, MessageType.Info, "Initializing NLB...");
                NLB.AdminInstance.Service.Proxy.Initialize();
            }

            public static void LoadWorkerServiceAssembly(string assemblyPath)
            {
                OnLog(NLB.AdminInstance, MessageType.Info, "Loading contract assembly...");
                NLB.AdminInstance.Service.Proxy.LoadWorkerServiceAssembly(File.ReadAllBytes(assemblyPath), Path.GetFileName(assemblyPath));
            }

            #region Events
            public static void OnNLBAdminServiceChange(AdminServiceUnit<IAdminNLBContract> unit, ServiceAvailabilityType availabilityType)
            {
                OnLog(null, MessageType.Info, string.Format("{0} is {1}.", unit, availabilityType));
                TryRaiseEvent(NLBAdminServiceChange, new AdminServiceEventArgs<IAdminNLBContract>(unit, availabilityType));
            }

            public static void OnSLBAdminServiceChange(AdminServiceUnit<IAdminSLBContract> unit, ServiceAvailabilityType availabilityType)
            {
                OnLog(null, MessageType.Info, string.Format("{0} is {1}.", unit, availabilityType));
                TryRaiseEvent(SLBAdminServiceChange, new AdminServiceEventArgs<IAdminSLBContract>(unit, availabilityType));
            }

            public static void OnWorkerAdminServiceChange(AdminServiceUnit<IAdminWorkerContract> unit, ServiceAvailabilityType availabilityType)
            {
                OnLog(null, MessageType.Info, string.Format("{0} is {1}.", unit, availabilityType));
                TryRaiseEvent(WorkerAdminServiceChange, new AdminServiceEventArgs<IAdminWorkerContract>(unit, availabilityType));
            }

            public static void OnSystemServiceChange(SystemServiceUnit unit, ServiceAvailabilityType availabilityType)
            {
                OnLog(null, MessageType.Info, string.Format("{0} is {1}.", unit, availabilityType));
                TryRaiseEvent(SystemServiceChange, new SystemServiceEventArgs(unit, availabilityType));
            }

            public static void OnWorkerServiceChange(WorkerServiceUnit unit, ServiceAvailabilityType availabilityType)
            {
                OnLog(null, MessageType.Info, string.Format("{0} is {1}.", unit, availabilityType));
                TryRaiseEvent(WorkerServiceChange, new WorkerServiceEventArgs(unit, availabilityType));
            }
            #endregion
        }
        #endregion

        //public static SystemServiceUnit Router
        //{
        //    get { return NLB.RouterService; }
        //}

        //public static SystemServiceUnit Proxy
        //{
        //    get { return NLB.ProxyService; }
        //}

        //public static ServiceProxy<TContract> CreateProxy<TContract>() where TContract : class
        //{
        //    if (Router.Status != ServiceStatus.Online)
        //    {
        //        OnLog(null, MessageType.Error, "Router is offline.");
        //        throw new FaultException("Router is offline.");
        //    }
        //    Binding binding = GenericConfiguration.GetMainBinding();
        //    return new ServiceProxy<TContract>(binding, new EndpointAddress(Router.Contracts[0].ListenUri.ToString()));
        //}

        internal static void OnLog(object sender, MessageType messageType, string message)
        {
            TryRaiseEvent(Log, sender, new LogEventArgs(messageType, string.Format("{0}\r\n", message)));
        }

        private static void TryRaiseEvent(Delegate handler, params object[] parameters)
        {
            if (handler == null)
            {
                return;
            }
            foreach (Delegate singleCast in handler.GetInvocationList())
            {
                ISynchronizeInvoke syncInvoke = singleCast.Target as ISynchronizeInvoke;
                try
                {
                    if (syncInvoke != null && syncInvoke.InvokeRequired)
                    {
                        syncInvoke.Invoke(singleCast, parameters);
                    }
                    else
                    {
                        singleCast.Method.Invoke(singleCast, parameters);
                    }
                }
                catch
                { }
            }

        }
    }
}
